// 头文件包含了函数声明，宏定义，结构体声明，变量声明。
// 比如stdio.h系统头文件包含了printf，scanf, fopen函数
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
// 介绍基础数据类型。
// 计算机储存：我们定义的变量，临时保存在内容(RAM)中的．以二进制方式保存．
// 位=1bit,最小单位，只能表示0,1。表示二进制。编程没有bit类型(bool类型实际占用空间为1byte。虽然有int i:1;这种定义，但是他实际占用空间4字节)。
// 字节Byte=8bits,基本存储单元。比如内存条为1T=1024G=2^10G=2^20M=2^30K=2^40byte的空间。
// 二进制     16进制 10进制
// b00000000 0x00   0
// b00000001 0x01   1
// b00000010 0x02   2
// b00000011 0x03   3
// b00000100 0x04   4
// b00000101 0x05   5
// b00000110 0x06   6
// b00000111 0x07   7
// b00001000 0x08   8
// b00001001 0x09   9
// b00001010 0x0a  10
// b00001011 0x0b  11
// b00001100 0x0c  12
// b00001101 0x0d  13
// b00001110 0x0e  14
// b00001111 0x0f  15
// b00010000 0x10  16
// b00010001 0x11  17
// ...
// b11111111 0xff  255
// 4位二进制刚好组成1位16进制

/*
二进制转十进制：B1010为例。
B    1    0    1    0
     *2^3 *2^2 *2^1 *2^0
     *8   *4   *2   *1
     1*8+ 0*4+ 1*2+ 0*1 = 10
结果为10.
*/

/*
十进制转二进制：10为例。
    2|___10___余0
    2|___5____余1
    2|___2____余0
         1____余1
结果为B1010
*/

// 二进制：b01101001,对应十进制105，对应16进制0X69。可以通过计算器程序员模式查看。
// 二进制计算跟十进制类似：
//   b01011101
// + b11100011
// =b101000000

// 计算机中。
// 一个字节(BYTE)无符号数，长度8bits，0-255对应0x00-0xff
// 一个字节(BYTE)有符号数，长度8bits，最高位0表示正，1表示负。他能表示-128到127

/*
补码及作用：正数直接表示为二进制即可，负数为其正数取反加一。作用是加减法，计算器方便直接执行加运算。
一个字节保存数据为例。
2=b00000010
-2则先用2=b00000010取反得到b11111101,然后加1得到b11111110。这就是计算机保存的内容。
试一下加法：2+(-2)=0
  b00000010
+ b11111110
=b100000000
由于用1个字节保存数据，溢出的位被舍弃。结果为0。
uint_8与int_8 ++情况一致。
*/

// 科普：CPU，内存（RAM重启丢失），硬盘（重启不丢失、可能也叫(nand/nor)flash，eeprom，emmc）。
// linux应用运行程序，从硬盘读取程序到内存运行。对于单片机，可以直接从flash运行程序．
// CPU做运算。
// RAM：读写速度快，断电数据丢失。
// ROM：读写稍慢，断电数据还在。
// 要实现一个1+2=3;首先有一个实现这个功能的程序，保存在硬盘。
// cpu将硬盘程序读取到内存中（linux，单片机可直接在flash运行），然后执行程序，在内存分别保存1和2.
// 然后将1和2放入CPU加法寄存器中，得到结果3，再放回内存。

// 内存以字节为单位存储，并为每一个字节的内存进行了编号。
// 字节Byte=8bits,基本存储单元。比如内存条为1T=1024G=2^10G=2^20M=2^30K=2^40byte的空间。

/*
类型                     占内存大小        表示范围
(signed) char           1字节            整数。(-2^7)到(2^7-1)
unsigned char           1字节            整数。(0)到(2^8-1)
short                   2字节            整数。(-2^15)到(2^15-1)
unsigned short          2字节            整数。(0)到(2^16-1)
int                     4字节            整数。(-2^31)到(2^31-1)       备注：STC51，int与short一致
unsigned int            4字节            整数。(0)到(2^32-1)           备注：STC51，unsigned int与unsigned short一致
long long               8字节            整数。(-2^63)到(2^63-1)        备注：STC51，不支持
unsigned long long      8字节            整数。(0)到(2^64-1) 备注：STC51，不支持
long                    备注：32位系统，long与int一致。64位系统，long与long long 保持一致。 备注：STC51，long=4字节
unsigned long           备注：32位系统，unsigned long与unsigned int一致。64位系统，unsigned long与unsigned long long 保持一致。备注：STC51，long=4字节
float                   4字节            负值：-3.402823E38 到 -1.401298E-45。正值：1.401298E-45 到 3.402823E38。 参考：https://learn.microsoft.com/zh-cn/office/vba/language/reference/user-interface-help/single-data-type
double                  8字节            负值：-1.79769313486231E308 到 -4.94065645841247E-324。正值：4.94065645841247E-324 到 1.79769313486232E308
*/

/*
printf("%d", a);
%d可以打印int类型。可能是c99之后有优化，%d也能正常打印char 和short；但打印long long或float或double还是会提示警告，表示可能不能正常打印。
而C51(可能是c89)，%d打印char类型不能正常打印。可以强制转为int类型！ printf("%d", (int)a);

*/
// int main(void)也是可以的
int main(int argc, char **argv)
{
    // 基础变量,可以用（关键字）sizeof查看占用内存大小
    //  %d有符号打印int能装下的整数。char, unsigned char，short, unsigned short, int, unsigned int，可以用%d打印出有符号的数据。
    //  %u无符号打印int能装下的整数。
    // char 是类型， value1是变量名字， = 表示赋值， 将-1赋值给value1
    // 我们定义的变量，系统是放在内存里的。
    char value1 = -1; // (-128到127)
    // sizeof返回值unsigned long类型，PC机需要用%lu， 32位系统用%u即可。
    // 这里会警告．%d接收长度是int长度，也就是４个字节，而64位电脑的sizeof返回的long是8字节．
    printf("char value:%d, memery size:%d\n", value1, sizeof(value1));
    // 或者用%d整数输出，把sizeof强制转化为int型即可。
    printf("char value:%d, memery size:%d\n", value1, (int)sizeof(value1));

    unsigned char value2 = -1; // (0到256)
    printf("unsigned char value:%d, memery size:%lu\n", value2, sizeof(value2));

    // %d打印int能装下的整数。short, unsigned short 2个字节，可以用%d打印。
    short value3 = -1; // ((-2^15) 到 (2^15 - 1))
    printf("short value:%d, memery size:%lu\n", value3, sizeof(value3));
    unsigned short value4 = -1; // (0 到 (2^16 - 1))
    printf("unsigned short value:%d, memery size:%lu\n", value4, sizeof(value4));

    // 对于51单片机，int占2字节；ARM，PC机等占4字节；。
    int value5 = -1; // ((-2^31) 到 (2^31 - 1))
    printf("int value:%d, memery size:%lu\n", value5, sizeof(value5));
    // %u无符号打印int能装下的整数。无符号整数赋值为-1，将他打印为有符号(%d)，
    unsigned int value6 = -1; // (0 到 (2^32 - 1))
    // %d，会把无符号int转为有符号int！
    printf("unsigned int value:%d, memery size:%lu\n", value6, sizeof(value6));
    printf("unsigned int value:%u, memery size:%lu\n", value6, sizeof(value6));

    // long long 占8字节。
    long long value9 = -1; // ((-2^63) 到 (2^63 - 1))
    printf("long long value:%lld, memery size:%lu\n", value9, sizeof(value9));
    unsigned long long value10 = -1; // (0 到 (2^64 - 1))
    printf("unsigned long long value:%llu, memery size:%lu\n", value10, sizeof(value10));

    // 在32位系统，long是4字节；在64位系统，long占8字节。
    long value7 = -1; // 32位系统，跟int一致．64位系统，跟long long 一致．
    printf("long value:%ld, memery size:%lu\n", value7, sizeof(value7));
    unsigned long value8 = -1; // 32位系统，跟unsigned　int一致．64位系统，跟unsigned　long long 一致．
    printf("unsigned long value:%lu, memery size:%lu\n", value8, sizeof(value8));

    float value11 = -1;
    printf("float value:%f, memery size:%lu\n", value11, sizeof(value11));

    double value12 = -1;
    printf("double value:%f, memery size:%lu\n", value12, sizeof(value12));
    // 用const修饰，表示常量。表示不能修改。
    // const int tmpConstValue = 1;
    // char buffer1[1];后面再说数据
    // short buffer1[2];
    // char *pointor;
    // struct xx value;
    // 因为返回类型是int，因此return 整数;
    return 1;
}

// 输出：
//  ./test a b c
//  hello world!
